package k8sutils

import (
	"strconv"

	redisv1beta2 "github.com/OT-CONTAINER-KIT/redis-operator/api/v1beta2"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type setupType string

const (
	standalone  setupType = "standalone"
	replication setupType = "replication"
	cluster     setupType = "cluster"
	sentinel    setupType = "sentinel"
)

// generateMetaInformation generates the meta information
func generateMetaInformation(resourceKind string, apiVersion string) metav1.TypeMeta {
	return metav1.TypeMeta{
		Kind:       resourceKind,
		APIVersion: apiVersion,
	}
}

// generateObjectMetaInformation generates the object meta information
func generateObjectMetaInformation(name string, namespace string, labels map[string]string, annotations map[string]string) metav1.ObjectMeta {
	return metav1.ObjectMeta{
		Name:        name,
		Namespace:   namespace,
		Labels:      labels,
		Annotations: annotations,
	}
}

// AddOwnerRefToObject adds the owner references to object
func AddOwnerRefToObject(obj metav1.Object, ownerRef metav1.OwnerReference) {
	obj.SetOwnerReferences(append(obj.GetOwnerReferences(), ownerRef))
}

// redisAsOwner generates and returns object reference
func redisAsOwner(cr *redisv1beta2.Redis) metav1.OwnerReference {
	trueVar := true
	return metav1.OwnerReference{
		APIVersion: cr.APIVersion,
		Kind:       cr.Kind,
		Name:       cr.Name,
		UID:        cr.UID,
		Controller: &trueVar,
	}
}

// redisClusterAsOwner generates and returns object reference
func redisClusterAsOwner(cr *redisv1beta2.RedisCluster) metav1.OwnerReference {
	trueVar := true
	return metav1.OwnerReference{
		APIVersion: cr.APIVersion,
		Kind:       cr.Kind,
		Name:       cr.Name,
		UID:        cr.UID,
		Controller: &trueVar,
	}
}

// redisReplicationAsOwner generates and returns object reference
func redisReplicationAsOwner(cr *redisv1beta2.RedisReplication) metav1.OwnerReference {
	trueVar := true
	return metav1.OwnerReference{
		APIVersion: cr.APIVersion,
		Kind:       cr.Kind,
		Name:       cr.Name,
		UID:        cr.UID,
		Controller: &trueVar,
	}
}

// RedisSentinelAsOwner generates and returns object reference
func redisSentinelAsOwner(cr *redisv1beta2.RedisSentinel) metav1.OwnerReference {
	trueVar := true
	return metav1.OwnerReference{
		APIVersion: cr.APIVersion,
		Kind:       cr.Kind,
		Name:       cr.Name,
		UID:        cr.UID,
		Controller: &trueVar,
	}
}

// generateStatefulSetsAnots generates and returns statefulsets annotations
func generateStatefulSetsAnots(stsMeta metav1.ObjectMeta, ignoreAnnots []string) map[string]string {
	anots := map[string]string{
		"redis.opstreelabs.in":       "true",
		"redis.opstreelabs.instance": stsMeta.GetName(),
	}
	for k, v := range stsMeta.GetAnnotations() {
		anots[k] = v
	}
	return filterAnnotations(anots, ignoreAnnots...)
}

// filterAnnotations Remove autogenerated annotations which pose no use to downstream objects (Services,Pods,etc)
func filterAnnotations(anots map[string]string, ignoreAnnots ...string) map[string]string {
	// Filter out some problematic annotations we don't want in the template.
	delete(anots, "kubectl.kubernetes.io/last-applied-configuration")
	delete(anots, "banzaicloud.com/last-applied")

	for _, ignoreAnnot := range ignoreAnnots {
		delete(anots, ignoreAnnot)
	}

	return anots
}

// generateServiceAnots generates and returns service annotations
func generateServiceAnots(stsMeta metav1.ObjectMeta, additionalSvcAnnotations map[string]string, epp exporterPortProvider) map[string]string {
	anots := map[string]string{
		"redis.opstreelabs.in":       "true",
		"redis.opstreelabs.instance": stsMeta.GetName(),
		"prometheus.io/scrape":       "true",
		"prometheus.io/port":         "9121",
	}
	if exporterPort, ok := epp(); ok {
		anots["prometheus.io/port"] = strconv.Itoa(exporterPort)
	}
	for k, v := range stsMeta.GetAnnotations() {
		anots[k] = v
	}
	for k := range additionalSvcAnnotations {
		anots[k] = additionalSvcAnnotations[k]
	}

	return filterAnnotations(anots)
}

// LabelSelectors generates object for label selection
func LabelSelectors(labels map[string]string) *metav1.LabelSelector {
	return &metav1.LabelSelector{MatchLabels: labels}
}

func getRedisLabels(name string, st setupType, role string, labels map[string]string) map[string]string {
	lbls := map[string]string{
		"app":              name,
		"redis_setup_type": string(st),
		"role":             role,
	}
	for k, v := range labels {
		lbls[k] = v
	}
	return lbls
}

func GetRedisReplicationLabels(cr *redisv1beta2.RedisReplication) map[string]string {
	return getRedisLabels(cr.GetName(), replication, "replication", cr.GetLabels())
}
